/* Copyright (C) 2010 Luca Piccinelli
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "prj_definitions.h"
#include "generators/resource/AbstractDirectoryGenerator.h"

#include <boost/filesystem.hpp>

#include <string>
#include <sstream>
#include <algorithm>

using namespace std;
using namespace boost::filesystem;

namespace NAMESPACE{

// ****** AbstractDirectoryGenerator implementation ****************************

//  _____________________________________________________
// |   Standard constructors                             |
// |_____________________________________________________|

AbstractDirectoryGenerator::~AbstractDirectoryGenerator(){
    if(is_open) close();
}

AbstractDirectoryGenerator::AbstractDirectoryGenerator() : AbstractResourceGenerator(),
                                                           elem_it(),
                                                           d_elems(){}
AbstractDirectoryGenerator::AbstractDirectoryGenerator(const AbstractDirectoryGenerator& g)
                                                       : AbstractResourceGenerator(g),
                                                         elem_it(g.elem_it),
                                                         d_elems(g.d_elems){}
AbstractDirectoryGenerator& AbstractDirectoryGenerator::operator=(const AbstractDirectoryGenerator& g){
    if(this == &g) return *this;

    AbstractResourceGenerator::operator =(g);
    elem_it = g.elem_it;
    d_elems = g.d_elems;

    return *this;
}
// ......................................................


//  _____________________________________________________
// |   Others constructors                               |
// |_____________________________________________________|

AbstractDirectoryGenerator::AbstractDirectoryGenerator(const string& _resource,
                                                       const memory_size_t& _max_mem)
                                                       : AbstractResourceGenerator(_resource, _max_mem),
                                                         elem_it(),
                                                         d_elems(){}
AbstractDirectoryGenerator::AbstractDirectoryGenerator(const IOKey& k,
                                                       const memory_size_t& _max_mem)
                                                       : AbstractResourceGenerator(k, _max_mem),
                                                         elem_it(),
                                                         d_elems(){}
AbstractDirectoryGenerator::AbstractDirectoryGenerator(const string& _resource,
                                                       const IOKey& k,
                                                       const memory_size_t& _max_mem)
                                                       : AbstractResourceGenerator(_resource, k, _max_mem),
                                                         elem_it(),
                                                         d_elems(){}

// ......................................................

//  _____________________________________________________
// |   Protected functions                               |
// |_____________________________________________________|

string AbstractDirectoryGenerator::next_element(){
    vector<path>::iterator end_it = d_elems.end();
    if(elem_it == end_it){
        close();
        return "";
    }

    string s = elem_it->string();
    elem_it++;

    return s;
}
// .......................................................

class CMP{
public:
    const bool operator()(const path& a, const path& b){
        return a.string() < b.string();
    }
};

AbstractDirectoryGenerator& AbstractDirectoryGenerator::open() throw(bad_resource){
    if(is_open) return *this;

    if(!exists(resource)){
        stringstream ss;
        ss << "The directory " << resource << " does not exist";
        throw bad_resource(ss.str());
    }

    directory_iterator d_it(resource);
    directory_iterator end_it;
    for(; d_it != end_it; d_it++){
        d_elems.push_back(d_it->path());
    }

    CMP cmp;
    std::sort(d_elems.begin(), d_elems.end(), cmp);
    elem_it = d_elems.begin();

    is_open = true;

    return *this;
}

AbstractDirectoryGenerator& AbstractDirectoryGenerator::close(){
    d_elems.clear();
    elem_it = d_elems.end();
    is_open = false;

    return *this;
}

// -----------------------------------------------------------------------------

}